import os
import re
import email
import base64
import shutil
from fastapi import APIRouter, Depends, Query, BackgroundTasks, Request, File, UploadFile, Form
from sqlalchemy.orm import Session
from typing import List, Optional
from pydantic import BaseModel
from sqlalchemy import or_, distinct
from datetime import datetime

from api.database import get_db
from api.model.user import User
from api.model.email_account import EmailAccount
from api.model.email import Email
from api.model.email_folder import EmailFolder
from api.controller.auth import get_current_user
from api.schemas.email.email import EmailResponse
from api.utils.response import success, fail
from api.service.email_service import EmailService
from api.utils.helpers import decode_url_encoded_str, encode_modified_utf7, decode_modified_utf7, add_target_blank_to_links
from api.controller.ws import manager as ws_manager
from api.utils.logger import get_logger
from api.utils.async_helper import run_in_executor

# 初始化日志
logger = get_logger("emails")

class EmailIdList(BaseModel):
    email_ids: List[int]

class MarkAllAsReadPayload(BaseModel):
    folder: str

class SendEmailPayload(BaseModel):
    draft_id: Optional[int] = None  # 关联的草稿ID
    to: str
    cc: Optional[str] = None
    subject: str
    body: str
    attachments: Optional[List[str]] = None  # 附件文件路径列表（备用）

class MoveEmailPayload(BaseModel):
    target_folder: str

router = APIRouter()

@router.get("")
async def get_emails(
    account_id: int,
    folder: Optional[str] = Query(None, description="邮件文件夹，不传则查询所有文件夹"),
    skip: int = Query(default=0, ge=0),
    limit: int = Query(default=100, ge=1, le=200),
    keyword: Optional[str] = Query(None, description="关键词，搜索标题和简介"),
    sender: Optional[str] = Query(None, description="发件人"),
    is_read: Optional[bool] = Query(None, description="是否已读"),
    is_sync: bool = Query(False, description="是否在获取列表前强制同步文件夹"),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    获取邮件列表
    在获取列表前，会先同步当前文件夹的最新邮件
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    if folder:
        folder = decode_url_encoded_str(folder)

    # 如果 is_sync 为 True，则在获取邮件列表之前先同步当前文件夹
    if is_sync:
        logger.info(f"收到强制同步请求，开始同步文件夹 '{folder}'")
        
        def sync_folder_task():
            try:
                email_service = EmailService(account=account)
                
                # 判断是否为虚拟文件夹或None
                virtual_folders = ["UNREAD", "STARRED", "FLAGGED"]
                
                if folder is None or folder.upper() in virtual_folders:
                    # UNREAD或None：同步INBOX即可（主要的未读邮件来源）
                    email_service._sync_folder_only({"original": "INBOX", "decoded": "INBOX", "flags": ""}, db)
                else:
                    # 获取文件夹在服务器上的原始名称
                    email_service._connect()
                    
                    # 查找文件夹的原始名称和flags
                    folder_info = None
                    try:
                        status, folder_list = email_service.imap.list()
                        if status == 'OK':
                            for folder_data in folder_list:
                                line_str = folder_data.decode('utf-8', 'ignore')
                                # 支持两种格式：name有引号和无引号
                                match = re.match(r'\((.*?)\)\s+"(.*?)"\s+"?(.*?)"?$', line_str)
                                if match:
                                    flags, _, original_name = match.groups()
                                    original_name = original_name.strip('"')  # 移除可能的引号
                                    decoded_name = decode_modified_utf7(original_name)
                                    
                                    # 检查特殊文件夹
                                    if folder == "Sent" and r'\Sent' in flags:
                                        folder_info = {"original": original_name, "decoded": "Sent", "flags": flags}
                                        break
                                    elif folder == "Junk" and r'\Junk' in flags:
                                        folder_info = {"original": original_name, "decoded": "Junk", "flags": flags}
                                        break
                                    elif folder == "Trash" and r'\Trash' in flags:
                                        folder_info = {"original": original_name, "decoded": "Trash", "flags": flags}
                                        break
                                    elif decoded_name == folder:
                                        folder_info = {"original": original_name, "decoded": decoded_name, "flags": flags}
                                        break
                    except Exception as e:
                        logger.error(f"获取文件夹信息失败: {e}")
                    
                    email_service._disconnect()
                    
                    if folder_info:
                        email_service._sync_folder_only(folder_info, db)
                    else:
                        # 如果找不到文件夹映射，使用默认值
                        logger.error(f"未找到文件夹 '{folder}' 的映射信息，使用默认同步")
                        encoded_folder = encode_modified_utf7(folder)
                        email_service._sync_folder_only({"original": encoded_folder, "decoded": folder, "flags": ""}, db)
                
                logger.info(f"文件夹 '{folder}' 同步完成")
            except Exception as e:
                logger.error(f"同步文件夹 '{folder}' 时出错: {e}", exc_info=True)
        
        try:
            # 异步执行同步操作
            await run_in_executor(sync_folder_task, timeout=180.0)
            
            # 同步完成后，广播未读计数更新
            import asyncio
            asyncio.create_task(ws_manager.broadcast_unread_count_update(current_user.id))
        except asyncio.TimeoutError:
            logger.error(f"同步文件夹 '{folder}' 超时（超过180秒），操作被强制取消。")
            # 同步失败不影响后续查询
        except Exception as e:
            logger.error(f"同步文件夹 '{folder}' 时发生未知错误: {e}", exc_info=True)
            # 同步失败不影响后续查询

    # 【改造】使用 EmailFolder 关联表查询
    # 基础查询：JOIN EmailFolder 表
    query = db.query(Email).join(
        EmailFolder, Email.id == EmailFolder.email_id
    ).filter(
        Email.email_account_id == account_id,
        EmailFolder.email_account_id == account_id
    )
    
    # 文件夹过滤逻辑
    if folder == "UNREAD":
        # UNREAD虚拟文件夹：查询所有未读邮件（包括Trash和Junk）
        query = query.filter(Email.is_read == False)
    elif folder is not None:
        # 指定文件夹：通过 EmailFolder 过滤
        query = query.filter(EmailFolder.folder_name == folder)
    # folder 为 None 时不过滤，查询所有文件夹

    # 其他过滤条件
    if sender:
        query = query.filter(Email.sender.contains(sender))
    
    if keyword:
        query = query.filter(
            or_(
                Email.subject.contains(keyword),
                Email.summary.contains(keyword)
            )
        )

    if is_read is not None:
        query = query.filter(Email.is_read == is_read)
    
    # 去重：同一封邮件可能在多个文件夹中
    query = query.distinct()
    
    # 排序和分页
    query = query.order_by(Email.received_date.desc())
    total = query.count()
    emails = query.offset(skip).limit(limit).all()
    
    # 【新增】为每封邮件添加所属的所有文件夹列表
    emails_response = []
    for email_obj in emails:
        email_dict = EmailResponse.from_orm(email_obj).dict()
        # 获取该邮件的所有文件夹
        email_dict['folders'] = [ef.folder_name for ef in email_obj.folders]
        emails_response.append(email_dict)
    
    return success(emails_response, count=total)

@router.get("/unread-counts")
async def get_unread_counts(
    account_id: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    获取指定账户下各文件夹的未读邮件数
    【新增】支持多文件夹关联统计
    注意：account_id 从路由前缀中获取，不需要在路径中重复定义
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")
    
    # 使用 EmailFolder 关联表统计各文件夹的未读数
    # 查询所有未读邮件的文件夹关联
    from sqlalchemy import func
    
    unread_counts = db.query(
        EmailFolder.folder_name,
        func.count(func.distinct(EmailFolder.email_id)).label('count')
    ).join(
        Email, Email.id == EmailFolder.email_id
    ).filter(
        EmailFolder.email_account_id == account_id,
        Email.email_account_id == account_id,
        Email.is_read == False
    ).group_by(
        EmailFolder.folder_name
    ).all()
    
    # 转换为字典格式
    result = {folder_name: count for folder_name, count in unread_counts}
    
    # 添加虚拟文件夹 UNREAD 的统计（包括所有文件夹）
    unread_total = db.query(func.count(func.distinct(Email.id))).join(
        EmailFolder, Email.id == EmailFolder.email_id
    ).filter(
        Email.email_account_id == account_id,
        Email.is_read == False
    ).scalar()
    
    result['UNREAD'] = unread_total or 0
    
    return success(result)

@router.get("/{email_id}")
async def get_email(
    account_id: int,
    email_id: int,
    background_tasks: BackgroundTasks,
    folder: str = Query(None, description="邮件所在的文件夹, 用于区分已发送邮件"),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    获取单封邮件详情
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    email_record = db.query(Email).filter(
        Email.id == email_id,
        Email.email_account_id == account_id
    ).first()

    if not email_record:
        return fail("邮件未找到")

    # 对于未读邮件，标记为已读
    if not email_record.is_read:
        def mark_as_read_task():
            email_service = EmailService(account=account)
            max_retries = 3
            retry_count = 0
            last_error = None
            
            while retry_count < max_retries:
                try:
                    email_service._connect()
                    
                    # 获取邮件的所有文件夹关联
                    folder_relations = db.query(EmailFolder).filter(
                        EmailFolder.email_id == email_id,
                        EmailFolder.email_account_id == account_id
                    ).all()
                    
                    # 在每个文件夹中标记为已读
                    failed_folders = []
                    for relation in folder_relations:
                        try:
                            original_folder_name = email_service._get_original_folder_name(relation.folder_name)
                            status, _ = email_service.imap.select(f'"{original_folder_name}"')
                            if status != 'OK':
                                failed_folders.append(relation.folder_name)
                                continue
                            
                            uid_str = str(relation.uid)
                            status, _ = email_service.imap.uid('store', uid_str, '+FLAGS', '(\\Seen)')
                            if status != 'OK':
                                failed_folders.append(relation.folder_name)
                                continue
                            
                            # 更新关联记录的 flags
                            if relation.flags:
                                if '\\Seen' not in relation.flags:
                                    relation.flags += ' \\Seen'
                            else:
                                relation.flags = '\\Seen'
                        except Exception as e:
                            logger.error(f"在文件夹 '{relation.folder_name}' 中标记邮件为已读失败: {e}")
                            failed_folders.append(relation.folder_name)
                    
                    email_service._disconnect()
                    
                    # 如果所有文件夹都失败，抛出异常触发重试
                    if len(failed_folders) == len(folder_relations):
                        raise Exception(f"所有文件夹标记失败: {', '.join(failed_folders)}")
                    
                    # 部分成功也算成功，更新本地状态
                    
                    # 更新邮件的全局已读状态
                    email_record.is_read = True
                    db.commit()
                    db.refresh(email_record)
                    return True
                    
                except Exception as e:
                    retry_count += 1
                    last_error = e
                    logger.error(f"标记邮件为已读失败（尝试 {retry_count}/{max_retries}）: {e}")
                    
                    if retry_count < max_retries:
                        import time
                        time.sleep(1 * retry_count)  # 递增延迟：1s, 2s
                    else:
                        # 所有重试都失败
                        db.rollback()
                        raise Exception(f"标记邮件为已读失败，请稍后重试: {str(last_error)}")
        
        try:
            await run_in_executor(mark_as_read_task, timeout=60.0)
            background_tasks.add_task(ws_manager.broadcast_unread_count_update, current_user.id)
        except Exception as e:
            return fail(str(e))

    # 在 Session 关闭前转换为字典
    email_data = EmailResponse.from_orm(email_record).dict()
    email_data['to'] = email_data.pop('recipients', None)

    return success(email_data)

@router.get("/{email_id}/content")
async def get_email_content(
    request: Request,
    account_id: int,
    email_id: int,
    folder: str = Query(None, description="邮件所在的文件夹, 用于区分已发送邮件"),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    获取解析后的邮件正文（HTML或纯文本），并处理内嵌图片
    【重构版】：按需从IMAP获取正文，不下载附件
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    email_record = db.query(Email).filter(
        Email.id == email_id,
        Email.email_account_id == account_id
    ).first()

    if not email_record:
        return fail("邮件记录未找到")

    # 使用新的按需获取方法
    email_service = EmailService(account=account)
    
    def fetch_content_task():
        # 1. 获取邮件正文内容（不含附件）
        text_body, html_body, inline_images = email_service.fetch_email_content_on_demand(db, email_record)
        
        # 2. 获取附件列表信息（不下载附件内容）
        attachments = email_service.fetch_email_attachments_info(db, email_record)
        
        # 3. 处理返回内容
        # 检查 text_body 是否实际上是 HTML 内容（被错误识别为纯文本）
        if html_body:
            content_to_return = html_body
        elif text_body and text_body.strip().startswith('<!'):
            # text_body 看起来像是 HTML，直接使用（不添加 <br>）
            content_to_return = text_body
        else:
            # 真正的纯文本，转换换行符为 <br>
            content_to_return = text_body.replace("\n", "<br>")
        
        # 4. 替换HTML中的cid链接为base64 data URI
        if html_body and inline_images:
            for cid, image in inline_images.items():
                b64_data = base64.b64encode(image["data"]).decode('utf-8')
                data_uri = f"data:{image['type']};base64,{b64_data}"
                content_to_return = content_to_return.replace(f"cid:{cid}", data_uri)
        
        # 5. 为所有链接添加 target="_blank" 属性
        content_to_return = add_target_blank_to_links(content_to_return)
        
        return {
            "content": content_to_return,
            "attachments": attachments
        }
    
    try:
        result = await run_in_executor(fetch_content_task, timeout=60.0)
        return success(result)
    except Exception as e:
        return fail(f"获取邮件内容失败: {str(e)}")

@router.get("/{email_id}/attachments/{attachment_index}")
async def download_attachment(
    account_id: int,
    email_id: int,
    attachment_index: int,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    下载邮件附件
    【重构版】：按需从IMAP获取单个附件
    """
    from fastapi.responses import Response
    
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    email_record = db.query(Email).filter(
        Email.id == email_id,
        Email.email_account_id == account_id
    ).first()

    if not email_record:
        return fail("邮件未找到")

    # 使用新的按需获取单个附件方法
    email_service = EmailService(account=account)
    
    def fetch_attachment_task():
        return email_service.fetch_single_attachment(db, email_record, attachment_index)
    
    try:
        filename, content_type, data = await run_in_executor(fetch_attachment_task, timeout=60.0)
        
        # 返回附件
        return Response(
            content=data,
            media_type=content_type,
            headers={
                'Content-Disposition': f'attachment; filename="{filename}"'
            }
        )
        
    except Exception as e:
        return fail(f"下载附件失败: {str(e)}")

@router.post("/{email_id}/move")
async def move_email(
    account_id: int,
    email_id: int,
    payload: MoveEmailPayload,
    source_folder: str = Query(..., description="源文件夹名称"),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    移动邮件到指定文件夹
    【改造】使用 EmailFolder 关联表
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    email_record = db.query(Email).filter(
        Email.id == email_id,
        Email.email_account_id == account_id
    ).first()
    
    if not email_record:
        return fail("邮件未找到")
    
    # 【改造】从 EmailFolder 关联表获取源文件夹信息
    source_relation = db.query(EmailFolder).filter(
        EmailFolder.email_id == email_id,
        EmailFolder.email_account_id == account_id,
        EmailFolder.folder_name == source_folder
    ).first()
    
    if not source_relation:
        return fail(f"邮件在文件夹 '{source_folder}' 中不存在")

    email_service = EmailService(account=account)
    
    def move_email_task():
        # 使用 EmailService 的移动方法，传递当前文件夹（源文件夹）和目标文件夹
        email_service.move_email(db, email_id, source_folder, payload.target_folder)
    
    try:
        await run_in_executor(move_email_task, timeout=60.0)
        return success(msg="邮件移动成功")
    except Exception as e:
        logger.error(f"移动邮件失败: {e}", exc_info=True)
        return fail(f"邮件移动失败: {str(e)}")

@router.put("/{email_id}/read")
async def mark_email_read(
    account_id: int,
    email_id: int,
    background_tasks: BackgroundTasks,
    is_read: bool = True,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    标记邮件为已读/未读
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")
    
    email_to_update = db.query(Email).filter(
        Email.id == email_id,
        Email.email_account_id == account_id
    ).first()
    
    if not email_to_update:
        return fail("邮件未找到")
    
    if email_to_update.is_read != is_read:
        def mark_read_task():
            email_service = EmailService(account=account)
            max_retries = 3
            retry_count = 0
            last_error = None
            
            while retry_count < max_retries:
                try:
                    email_service._connect()
                    
                    # 获取邮件的所有文件夹关联
                    folder_relations = db.query(EmailFolder).filter(
                        EmailFolder.email_id == email_id,
                        EmailFolder.email_account_id == account_id
                    ).all()
                    
                    # 在每个文件夹中更新状态
                    failed_folders = []
                    for relation in folder_relations:
                        try:
                            original_folder_name = email_service._get_original_folder_name(relation.folder_name)
                            status, _ = email_service.imap.select(f'"{original_folder_name}"')
                            if status != 'OK':
                                failed_folders.append(relation.folder_name)
                                continue
                            
                            uid_str = str(relation.uid)
                            
                            if is_read:
                                status, _ = email_service.imap.uid('store', uid_str, '+FLAGS', '(\\Seen)')
                                if status == 'OK':
                                    # 更新 flags
                                    if relation.flags and '\\Seen' not in relation.flags:
                                        relation.flags += ' \\Seen'
                                    elif not relation.flags:
                                        relation.flags = '\\Seen'
                                else:
                                    failed_folders.append(relation.folder_name)
                            else:
                                status, _ = email_service.imap.uid('store', uid_str, '-FLAGS', '(\\Seen)')
                                if status == 'OK':
                                    # 更新 flags
                                    if relation.flags:
                                        relation.flags = relation.flags.replace('\\Seen', '').strip()
                                else:
                                    failed_folders.append(relation.folder_name)
                        except Exception as e:
                            logger.error(f"在文件夹 '{relation.folder_name}' 中更新状态失败: {e}")
                            failed_folders.append(relation.folder_name)
                    
                    email_service._disconnect()
                    
                    # 如果所有文件夹都失败，抛出异常触发重试
                    if len(failed_folders) == len(folder_relations):
                        raise Exception(f"所有文件夹更新失败: {', '.join(failed_folders)}")
                    
                    # 部分成功也算成功
                    
                    # 更新邮件的全局状态
                    email_to_update.is_read = is_read
                    db.commit()
                    return True
                    
                except Exception as e:
                    retry_count += 1
                    last_error = e
                    logger.error(f"更新邮件状态失败（尝试 {retry_count}/{max_retries}）: {e}", exc_info=True)
                    
                    if retry_count < max_retries:
                        import time
                        time.sleep(1 * retry_count)  # 递增延迟
                    else:
                        # 所有重试都失败
                        db.rollback()
                        raise Exception(f"更新邮件状态失败，请稍后重试: {str(last_error)}")
        
        try:
            await run_in_executor(mark_read_task, timeout=60.0)
            background_tasks.add_task(ws_manager.broadcast_unread_count_update, current_user.id)
        except Exception as e:
            return fail(str(e))

    return success(msg="邮件状态更新成功")

@router.post("/mark-as-unread")
async def mark_emails_as_unread(
    account_id: int,
    payload: EmailIdList,
    background_tasks: BackgroundTasks,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    批量标记邮件为未读
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    emails_to_mark = db.query(Email).filter(
        Email.id.in_(payload.email_ids),
        Email.email_account_id == account_id
    ).all()

    if not emails_to_mark:
        return fail("未找到要标记的邮件")

    def mark_unread_task():
        # 【改造】处理多文件夹关联
        email_service = EmailService(account=account)
        email_service._connect()
        
        updated = False
        for email_item in emails_to_mark:
            if email_item.is_read:
                # 获取该邮件的所有文件夹关联
                folder_relations = db.query(EmailFolder).filter(
                    EmailFolder.email_id == email_item.id,
                    EmailFolder.email_account_id == account_id
                ).all()
                
                # 在每个文件夹中标记为未读
                for relation in folder_relations:
                    try:
                        original_folder_name = email_service._get_original_folder_name(relation.folder_name)
                        email_service.imap.select(f'"{original_folder_name}"')
                        uid_str = str(relation.uid)
                        email_service.imap.uid('store', uid_str, '-FLAGS', '(\\Seen)')
                        # 更新 flags
                        if relation.flags:
                            relation.flags = relation.flags.replace('\\Seen', '').strip()
                    except Exception as e:
                        logger.error(f"在文件夹 '{relation.folder_name}' 中标记未读失败: {e}")
                
                email_item.is_read = False
                updated = True
        
        email_service._disconnect()
        
        if updated:
            db.commit()
        
        return updated
    
    try:
        updated = await run_in_executor(mark_unread_task, timeout=60.0)
        if updated:
            background_tasks.add_task(ws_manager.broadcast_unread_count_update, current_user.id)
        return success(msg="邮件已批量标记为未读")
    except Exception as e:
        db.rollback()
        logger.error(f"批量标记邮件为未读失败: {e}", exc_info=True)
        return fail(f"批量标记邮件为未读失败: {e}")

@router.post("/mark-as-read")
async def mark_emails_as_read(
    account_id: int,
    payload: EmailIdList,
    background_tasks: BackgroundTasks,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    批量标记邮件为已读
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    emails_to_mark = db.query(Email).filter(
        Email.id.in_(payload.email_ids),
        Email.email_account_id == account_id
    ).all()

    if not emails_to_mark:
        return fail("未找到要标记的邮件")

    def mark_read_batch_task():
        email_service = EmailService(account=account)
        max_retries = 3
        retry_count = 0
        last_error = None
        
        while retry_count < max_retries:
            try:
                email_service._connect()
                
                updated = False
                all_failed = True
                
                for email_item in emails_to_mark:
                    if not email_item.is_read:
                        # 获取该邮件的所有文件夹关联
                        folder_relations = db.query(EmailFolder).filter(
                            EmailFolder.email_id == email_item.id,
                            EmailFolder.email_account_id == account_id
                        ).all()
                        
                        # 在每个文件夹中标记为已读
                        email_failed = True
                        for relation in folder_relations:
                            try:
                                original_folder_name = email_service._get_original_folder_name(relation.folder_name)
                                status, _ = email_service.imap.select(f'"{original_folder_name}"')
                                if status != 'OK':
                                    continue
                                
                                uid_str = str(relation.uid)
                                status, _ = email_service.imap.uid('store', uid_str, '+FLAGS', '(\\Seen)')
                                if status == 'OK':
                                    # 更新 flags
                                    if relation.flags and '\\Seen' not in relation.flags:
                                        relation.flags += ' \\Seen'
                                    elif not relation.flags:
                                        relation.flags = '\\Seen'
                                    email_failed = False
                            except Exception as e:
                                logger.error(f"在文件夹 '{relation.folder_name}' 中标记已读失败: {e}")
                        
                        # 只要有一个文件夹成功，就更新本地状态
                        if not email_failed:
                            email_item.is_read = True
                            updated = True
                            all_failed = False
                
                email_service._disconnect()
                
                # 如果所有邮件都失败，抛出异常触发重试
                if all_failed and len([e for e in emails_to_mark if not e.is_read]) > 0:
                    raise Exception("所有邮件标记已读失败")
                
                if updated:
                    db.commit()
                
                return updated
                
            except Exception as e:
                retry_count += 1
                last_error = e
                logger.error(f"批量标记邮件为已读失败（尝试 {retry_count}/{max_retries}）: {e}", exc_info=True)
                
                if retry_count < max_retries:
                    import time
                    time.sleep(1 * retry_count)
                else:
                    db.rollback()
                    raise Exception(f"批量标记邮件为已读失败，请稍后重试: {str(last_error)}")
    
    try:
        updated = await run_in_executor(mark_read_batch_task, timeout=60.0)
        if updated:
            background_tasks.add_task(ws_manager.broadcast_unread_count_update, current_user.id)
        return success(msg="邮件已批量标记为已读")
    except Exception as e:
        return fail(str(e))

@router.post("/mark-all-as-read")
async def mark_all_as_read(
    account_id: int,
    payload: MarkAllAsReadPayload,
    background_tasks: BackgroundTasks,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    将特定文件夹中的所有邮件标记为已读
    【v2.0改造】使用EmailFolder关联表
    """
    logger.info(f"[标记全部已读] 开始 - 账户ID:{account_id}, 文件夹:{payload.folder}")
    
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    # 【改造】使用EmailFolder关联表查询
    query = db.query(Email).join(
        EmailFolder, Email.id == EmailFolder.email_id
    ).filter(
        Email.email_account_id == account_id,
        EmailFolder.email_account_id == account_id,
        Email.is_read == False
    )

    # 文件夹过滤
    if payload.folder == "UNREAD":
        # UNREAD 是虚拟文件夹，包含所有文件夹的未读邮件（包括Trash和Junk）
        pass  # 不需要额外过滤
    elif payload.folder:
        query = query.filter(EmailFolder.folder_name == payload.folder)

    emails_to_mark = query.distinct().all()
    
    logger.info(f"[标记全部已读] 找到 {len(emails_to_mark)} 封未读邮件")
    
    if not emails_to_mark:
        return success(msg="没有需要标记的邮件")

    def mark_all_read_task():
        email_service = EmailService(account=account)
        max_retries = 3
        retry_count = 0
        last_error = None
        
        while retry_count < max_retries:
            try:
                logger.info(f"[标记全部已读] 尝试 {retry_count + 1}/{max_retries}")
                email_service._connect()
                
                # 获取所有需要标记的邮件的文件夹关联
                from collections import defaultdict
                folder_relations_by_folder = defaultdict(list)
                
                for email_item in emails_to_mark:
                    # 获取该邮件在所有文件夹中的关联（不过滤）
                    # 目的：将邮件在其存在的所有文件夹中都标记为已读
                    relations = db.query(EmailFolder).filter(
                        EmailFolder.email_id == email_item.id,
                        EmailFolder.email_account_id == account_id
                    ).all()
                    
                    for relation in relations:
                        folder_relations_by_folder[relation.folder_name].append(relation)
                
                logger.info(f"[标记全部已读] 按文件夹分组: {dict((k, len(v)) for k, v in folder_relations_by_folder.items())}")
                
                # 对每个文件夹批量标记
                all_failed = True
                failed_folders = []
                success_count = 0
                
                for folder_name, relations in folder_relations_by_folder.items():
                    try:
                        logger.info(f"[标记全部已读] 处理文件夹 '{folder_name}', {len(relations)} 封邮件")
                        original_folder_name = email_service._get_original_folder_name(folder_name)
                        logger.info(f"[标记全部已读] 原始文件夹名: {original_folder_name}")
                        
                        status, _ = email_service.imap.select(f'"{original_folder_name}"')
                        logger.info(f"[标记全部已读] SELECT 状态: {status}")
                        if status != 'OK':
                            failed_folders.append(folder_name)
                            continue
                        
                        # 批量标记：将所有UID组合成逗号分隔的字符串
                        uid_list = ','.join([str(rel.uid) for rel in relations])
                        logger.info(f"[标记全部已读] 标记UIDs: {uid_list}")
                        
                        status, response = email_service.imap.uid('store', uid_list, '+FLAGS', '(\\Seen)')
                        logger.info(f"[标记全部已读] STORE 状态: {status}, 响应: {response}")
                        
                        if status == 'OK':
                            # 更新关联表的flags
                            for rel in relations:
                                if rel.flags and '\\Seen' not in rel.flags:
                                    rel.flags += ' \\Seen'
                                elif not rel.flags:
                                    rel.flags = '\\Seen'
                            all_failed = False
                            success_count += len(relations)
                            logger.info(f"[标记全部已读] ✓ 文件夹 '{folder_name}' 标记成功")
                        else:
                            failed_folders.append(folder_name)
                            logger.error(f"[标记全部已读] ✗ 文件夹 '{folder_name}' STORE返回非OK状态")
                    except Exception as e:
                        logger.error(f"[标记全部已读] ✗ 文件夹 '{folder_name}' 批量标记失败: {e}", exc_info=True)
                        failed_folders.append(folder_name)
                
                email_service._disconnect()
                logger.info(f"[标记全部已读] IMAP连接已断开")
                
                # 如果所有文件夹都失败，抛出异常触发重试
                if all_failed:
                    logger.error(f"[标记全部已读] 所有文件夹都失败: {', '.join(failed_folders)}")
                    raise Exception(f"所有文件夹标记失败: {', '.join(failed_folders)}")
                
                # 部分成功也算成功

                # 批量更新邮件的全局已读状态
                email_ids = [email.id for email in emails_to_mark]
                logger.info(f"[标记全部已读] 更新数据库: {len(email_ids)} 封邮件")
                
                db.query(Email).filter(Email.id.in_(email_ids)).update(
                    {Email.is_read: True},
                    synchronize_session=False
                )
                db.commit()
                logger.info(f"[标记全部已读] 数据库更新完成并已提交")
                
                logger.info(f"[标记全部已读] ✓ 操作完成: {len(emails_to_mark)} 封邮件已标记为已读")
                return len(emails_to_mark)
                
            except Exception as e:
                retry_count += 1
                last_error = e
                logger.error(f"批量标记已读失败（尝试 {retry_count}/{max_retries}）: {e}")
                
                if retry_count < max_retries:
                    import time
                    time.sleep(1 * retry_count)
                else:
                    db.rollback()
                    raise Exception(f"批量标记已读失败，请稍后重试: {str(last_error)}")
    
    try:
        count = await run_in_executor(mark_all_read_task, timeout=60.0)
        background_tasks.add_task(ws_manager.broadcast_unread_count_update, current_user.id)
        return success(msg=f"操作完成，{count} 封邮件已标记为已读。")
    except Exception as e:
        return fail(str(e))

@router.delete("")
async def delete_emails(
    account_id: int,
    payload: EmailIdList,
    background_tasks: BackgroundTasks,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    批量删除邮件(移动到已删除文件夹)
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    email_service = EmailService(account=account)
    try:
        # 注意：在调用 move_emails_to_trash 之前，需要先关闭现有的数据库会话
        # 因为该方法会自己创建新的会话。或者改造 EmailService 以接收现有会-话。
        # 为简单起见，这里我们直接调用，依赖其内部的会话管理。
        # 如果遇到会话问题，需要回来调整。
        email_service.move_emails_to_trash(db, payload.email_ids)
        
        background_tasks.add_task(ws_manager.broadcast_unread_count_update, current_user.id)
        return success(msg="邮件已成功移动到回收站")
    except Exception as e:
        return fail(f"移动邮件到回收站失败: {str(e)}")

@router.delete("/{email_id}")
async def permanent_delete_email(
    account_id: int,
    email_id: int,
    background_tasks: BackgroundTasks,
    folder: str = Query(None, description="邮件所在的文件夹"),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    彻底删除单封邮件
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    email_to_delete = db.query(Email).filter(
        Email.id == email_id,
        Email.email_account_id == account_id
    ).first()

    if not email_to_delete:
        return fail("未找到要删除的邮件")

    # 使用 EmailService 删除单个邮件
    email_service = EmailService(account=account)
    
    def permanent_delete_task():
        return email_service.permanent_delete_emails(db, [email_id])
    
    try:
        success_flag, error_message = await run_in_executor(permanent_delete_task, timeout=60.0)
        
        if success_flag:
            background_tasks.add_task(ws_manager.broadcast_unread_count_update, current_user.id)
            return success(msg="邮件已彻底删除")
        else:
            return fail(error_message)
    except Exception as e:
        return fail(f"彻底删除邮件失败: {str(e)}")

@router.post("/permanent-delete")
async def permanent_delete_selected_emails(
    account_id: int,
    payload: EmailIdList,
    background_tasks: BackgroundTasks,
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    批量彻底删除邮件
    """
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    # 使用 EmailService 批量删除邮件
    email_service = EmailService(account=account)
    
    def permanent_delete_batch_task():
        return email_service.permanent_delete_emails(db, payload.email_ids)
    
    try:
        success_flag, error_message = await run_in_executor(permanent_delete_batch_task, timeout=60.0)
        
        if success_flag:
            background_tasks.add_task(ws_manager.broadcast_unread_count_update, current_user.id)
            return success(msg=error_message)
        else:
            return fail(error_message)
    except Exception as e:
        return fail(f"批量彻底删除邮件失败: {str(e)}")

@router.post("/send")
async def send_email(
    request: Request,
    account_id: int,
    to: str = Form(...),
    subject: str = Form(...),
    body: str = Form(...),
    cc: str = Form(None),
    draft_id: int = Form(None),
    attachments: List[UploadFile] = File(default=[]),
    current_user: User = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    发送邮件，支持内嵌图片和附件
    """
    from api.model.draft import Draft
    import mimetypes
    
    account = db.query(EmailAccount).filter(
        EmailAccount.id == account_id,
        EmailAccount.user_id == current_user.id
    ).first()
    if not account:
        return fail("邮箱账户未找到")

    # 验证必填字段
    if not to or not to.strip():
        return fail("收件人不能为空")
    if not subject or not subject.strip():
        return fail("主题不能为空")
    if not body or not body.strip():
        return fail("正文不能为空")
    
    logger.info(f"发送邮件 - 收件人: {to}, 主题: {subject}, 上传附件数: {len(attachments) if attachments else 0}")
    
    # 提取正文中的图片并转换为内嵌图片（cid）
    inline_images_list = []
    image_pattern = re.compile(r'src="(/uploads/images/([^"]+))"')
    
    def replace_image(match):
        img_path = match.group(1)  # /uploads/images/xxx.jpg
        img_filename = match.group(2)  # xxx.jpg
        full_path = img_path.lstrip('/')  # uploads/images/xxx.jpg
        
        if os.path.exists(full_path):
            # 生成唯一的 cid
            cid = f"image_{len(inline_images_list)}_{img_filename}"
            inline_images_list.append({
                'path': full_path,
                'cid': cid,
                'filename': img_filename
            })
            return f'src="cid:{cid}"'
        else:
            return match.group(0)
    
    # 替换所有图片为 cid
    body = image_pattern.sub(replace_image, body)
    
    logger.info(f"找到 {len(inline_images_list)} 个内嵌图片")
    
    # 获取草稿附件（如果有draft_id）
    draft_attachments_list = []
    if draft_id:
        draft_dir = os.path.join("runtime", "files", "drafts", str(draft_id))
        if os.path.exists(draft_dir):
            for filename in os.listdir(draft_dir):
                file_path = os.path.join(draft_dir, filename)
                if os.path.isfile(file_path):
                    draft_attachments_list.append({
                        'path': file_path,
                        'filename': filename
                    })
            logger.info(f"草稿 {draft_id} 有 {len(draft_attachments_list)} 个附件")
    
    # 处理上传的附件（保存到临时文件）
    uploaded_attachments_list = []
    if attachments:
        for attachment in attachments:
            try:
                content = await attachment.read()
                # 保存到临时文件
                temp_dir = os.path.join("runtime", "files", "temp")
                os.makedirs(temp_dir, exist_ok=True)
                temp_path = os.path.join(temp_dir, attachment.filename)
                with open(temp_path, 'wb') as f:
                    f.write(content)
                
                uploaded_attachments_list.append({
                    'path': temp_path,
                    'filename': attachment.filename
                })
                logger.info(f"✓ 临时保存上传附件: {attachment.filename}")
            except Exception as e:
                logger.error(f"✗ 保存上传附件失败 {attachment.filename}: {e}", exc_info=True)
                return fail(f"保存附件失败: {attachment.filename}")
    
    # 合并所有附件
    all_attachments = uploaded_attachments_list + draft_attachments_list
    
    def send_email_task():
        # 使用 EmailService 发送邮件
        email_service = EmailService(account=account)
        success_flag, error_message = email_service.send_email(
            to=to,
            subject=subject,
            body=body,
            cc=cc,
            attachments=all_attachments,
            inline_images=inline_images_list
        )
        
        # 清理临时文件
        for att in uploaded_attachments_list:
            try:
                if os.path.exists(att['path']):
                    os.remove(att['path'])
            except Exception as e:
                logger.error(f"清理临时文件失败 {att['path']}: {e}")
        
        if not success_flag:
            raise Exception(error_message)
        
        # 同步 Sent 文件夹
        try:
            # 获取 Sent 文件夹信息
            email_service._connect()
            folder_info = None
            try:
                status, folder_list = email_service.imap.list()
                if status == 'OK':
                    for folder_data in folder_list:
                        line_str = folder_data.decode('utf-8', 'ignore')
                        # 支持两种格式：name有引号和无引号
                        match = re.match(r'\((.*?)\)\s+"(.*?)"\s+"?(.*?)"?$', line_str)
                        if match:
                            flags, _, original_name = match.groups()
                            original_name = original_name.strip('"')  # 移除可能的引号
                            if r'\Sent' in flags:
                                folder_info = {"original": original_name, "decoded": "Sent", "flags": flags}
                                break
            except Exception as e:
                logger.error(f"获取 Sent 文件夹信息失败: {e}")
            
            email_service._disconnect()
            
            if folder_info:
                email_service._sync_folder_only(folder_info, db)
                logger.info("已同步 Sent 文件夹")
        except Exception as e:
            logger.error(f"同步 Sent 文件夹失败: {e}")

        # 如果有关联的草稿，发送成功后删除它及其附件
        if draft_id:
            draft_to_delete = db.query(Draft).filter(Draft.id == draft_id).first()
            if draft_to_delete:
                # 删除草稿附件文件夹
                draft_dir = os.path.join("runtime", "files", "drafts", str(draft_id))
                if os.path.exists(draft_dir):
                    try:
                        shutil.rmtree(draft_dir)
                    except Exception as e:
                        logger.error(f"删除草稿附件文件夹失败: {e}")
                
                db.delete(draft_to_delete)
                db.commit()

        return error_message
    
    try:
        message = await run_in_executor(send_email_task, timeout=60.0)
        return success(msg=message)
    except Exception as e:
        return fail(str(e))
